//  Copyright 2008 Stefan Kristiansson
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the Lesser GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  Lesser GNU General Public License for more details.
//
//  You should have received a copy of the Lesser GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

// CemeWrapper.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#pragma managed
#include <vcclr.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#using <mscorlib.dll>
using namespace System;
using namespace System::Runtime::InteropServices;

#if DEBUG
#using "..\Ceme\bin\Debug\Ceme.dll"
#else
#using "..\Ceme\bin\Release\Ceme.dll"
#endif
using namespace Ceme;
using namespace System::Collections::Generic;
ref class Globals {
public:	
	static CemeParser ^parser;
}; 

void init() 
{
	Globals::parser = gcnew CemeParser();
}
double evaluate() 
{
	return Globals::parser->Evaluate();
}
void setExpression(char *expression)
{
	String ^expr = gcnew String(expression);
	Globals::parser->SetExpression(expr);
}
int getVariableCount()
{
	array<String^>^ sVars = Globals::parser->GetVariables();
	return sVars->Length;
}
char* getVariable(int index)
{
	array<String^>^ sVars = Globals::parser->GetVariables();
	int i=0;
	if (index >= sVars->Length)
		return NULL;
	pin_ptr<const wchar_t> wch = PtrToStringChars(sVars[index]);
	size_t convertedChars = 0;
	size_t sizeInBytes = ((sVars[index]->Length + 1) * 2);
	errno_t err = 0;
	pin_ptr<char> cVar = (char *)malloc(sizeInBytes);
	err = wcstombs_s(&convertedChars, 
					 cVar, sizeInBytes,
					 wch, sizeInBytes);
	return cVar;
}
int setVariable(char* variable, double value) 
{
	String ^sVar = gcnew String(variable);
	return Globals::parser->SetVariable(sVar,value);
}
int addFunction(char* name, int numArg, double (*function)(double *args))
{
	String^ sName = gcnew String(name);
	CemeParser::ProcessFunctionCB^ functionDelegate = (CemeParser::ProcessFunctionCB^)Marshal::GetDelegateForFunctionPointer((IntPtr)function, CemeParser::ProcessFunctionCB::typeid );
	return Globals::parser->AddFunction(sName, numArg, functionDelegate);
}
#pragma unmanaged
extern "C" {
	__declspec(dllexport) int CemeAddFunction(char* name, int numArg, double (*function)(double *args))
	{
		return addFunction(name, numArg, function);
	}
	__declspec(dllexport) int CemeSetVariable(char* variable, double value)
	{
		return setVariable(variable, value);
	}

	__declspec(dllexport) char* CemeGetVariable(int index)
	{
		return getVariable(index);
	}
	__declspec(dllexport) int CemeGetVariableCount()
	{
		return getVariableCount();
	}

	__declspec(dllexport) double CemeEvaluate()
	{
		return evaluate();
	}
	__declspec(dllexport) void CemeSetExpression(char *expression)
	{
		setExpression(expression);
	}
	__declspec(dllexport) void CemeInit()
	{
		init();
	}
	BOOL APIENTRY DllMain( HMODULE hModule,
						   DWORD  ul_reason_for_call,
						   LPVOID lpReserved
						 )
	{
		return TRUE;
	}

}